package edu.ccut.saturn.studio.logic;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import org.eclipse.wst.sse.ui.StructuredTextEditor;
import org.w3c.dom.Document;

import edu.ccut.saturn.studio.core.util.eclipse.SaturnProjectUtil;
import edu.ccut.saturn.studio.logic.contextaction.IEditorMultiPage;
import edu.ccut.saturn.studio.logic.model.Shape;
import edu.ccut.saturn.studio.logic.model.ShapesDiagram;
import edu.ccut.saturn.studio.logic.model.commands.FakeCommand;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnComponentNode;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnCreatComponentNode;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnEndIterationNode;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnEndNode;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnPropertyNode;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnStartIterationNode;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnTransactionBeginNode;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnTransactionCommitNode;
import edu.ccut.saturn.studio.logic.model.saturn.SaturnTransactionRollBackNode;
import edu.ccut.saturn.studio.logic.model.saturn.action.SaturnDecisionNodeInAction;
import edu.ccut.saturn.studio.logic.model.saturn.action.SaturnInformationNodeInAction;
import edu.ccut.saturn.studio.logic.model.saturn.action.SaturnLogicInAction;
import edu.ccut.saturn.studio.logic.model.saturn.action.SaturnStartNodeInAction;
import edu.ccut.saturn.studio.logic.model.saturn.logic.SaturnDecisionNodeInLogic;
import edu.ccut.saturn.studio.logic.model.saturn.logic.SaturnInformationNodeInLogic;
import edu.ccut.saturn.studio.logic.model.saturn.logic.SaturnLogicInLogic;
import edu.ccut.saturn.studio.logic.model.saturn.logic.SaturnStartNodeInLogic;
import edu.ccut.saturn.studio.logic.model.xml.ModelXmlUtils;
import edu.ccut.saturn.studio.logic.model.xml.loader.ComponentNodeLoader;
import edu.ccut.saturn.studio.logic.model.xml.loader.DataMappingLoader;
import edu.ccut.saturn.studio.logic.model.xml.loader.EndIterationNodeLoader;
import edu.ccut.saturn.studio.logic.model.xml.loader.EndNodeLoader;
import edu.ccut.saturn.studio.logic.model.xml.loader.NodeLoader;
import edu.ccut.saturn.studio.logic.model.xml.loader.StartIterationLoader;
import edu.ccut.saturn.studio.logic.model.xml.loader.SwichNodeLoader;
import edu.ccut.saturn.studio.logic.model.xml.loader.TransactionBenginLoader;
import edu.ccut.saturn.studio.logic.model.xml.loader.TransactionCommitLoader;
import edu.ccut.saturn.studio.logic.model.xml.loader.TransactionRollbackLoader;
import edu.ccut.saturn.studio.logic.model.xml.loader.WorkflowInLogicNodeLoader;
import edu.ccut.saturn.studio.logic.model.xml.loader.logic.LogicNodeInLogicLoader;
import edu.ccut.saturn.studio.logic.model.xml.loader.logic.StartNodeInLogicLoader;
import edu.ccut.saturn.studio.logic.model.xml.loader.logic.SaturnDecisionNodeInLogicLoader;
import edu.ccut.saturn.studio.logic.model.xml.loader.logic.SaturnInformationNodeInLogicLoader;

public class LogicMultiPageEditor extends MultiPageEditorPart implements
		IResourceChangeListener, ITabbedPropertySheetPageContributor,
		IEditorMultiPage {

	private static final String LOGIC_MULTIF_SOURCE = "source";

	private static final String LOGIC_MULTIF_LOW = "view";

	private LogicEditor logicEditor;

	private StructuredTextEditor textEditor;

	private int textEditorIndex = 0;

	private Document document;

	private List<Class<?>> child = new ArrayList<Class<?>>();

	public StructuredTextEditor getTextEditor() {
		return textEditor;
	}

	public LogicEditor getShapesEditor() {
		return logicEditor;
	}

	private void createGraphicalEditPage() {
		try {
			List<Shape> shapes = ModelXmlUtils.loadModels(this.document,
					new NodeLoader[] { new SaturnInformationNodeInLogicLoader(),
							new ComponentNodeLoader(),
							new StartNodeInLogicLoader(),
							new EndNodeLoader(),
							new SaturnDecisionNodeInLogicLoader(),
							new StartIterationLoader(),
							new EndIterationNodeLoader(),
							new LogicNodeInLogicLoader(),
							new TransactionBenginLoader(),
							new TransactionCommitLoader(),
							new TransactionRollbackLoader(),
							new WorkflowInLogicNodeLoader(),
							new DataMappingLoader(), new SwichNodeLoader() });

			this.logicEditor = new LogicEditor(shapes, this.document);
			int shapesEditorIndex = addPage(logicEditor, getEditorInput());
			setPageText(shapesEditorIndex, LOGIC_MULTIF_LOW);
			setPartName(getEditorInput().getName());
			this.logicEditor.getDiagram().removeModifyShapes();
			this.setActivePage(shapesEditorIndex);
		} catch (PartInitException e) {
			e.printStackTrace();
		}
	}

	private void createSourcePage() {
		try {
			textEditor = new StructuredTextEditor();
			this.textEditorIndex = addPage(textEditor, getEditorInput());

			setPageText(this.textEditorIndex, LOGIC_MULTIF_SOURCE);
			this.document = getDocument(textEditor);
		} catch (PartInitException e) {
			e.printStackTrace();
		}
	}

	private Document getDocument(StructuredTextEditor source) {
		Document document = (Document) source.getAdapter(Document.class);
		if (document.getDocumentElement() == null) {
			SaturnProjectUtil.refreshProject(getEditorInput());
		}
		
		return document;
	}

	protected void createPages() {
		createSourcePage();
		createGraphicalEditPage();

		this.child.add(SaturnStartNodeInLogic.class);
		this.child.add(SaturnComponentNode.class);
		this.child.add(SaturnInformationNodeInLogic.class);
		this.child.add(SaturnEndNode.class);
		this.child.add(SaturnLogicInLogic.class);
		this.child.add(SaturnDecisionNodeInLogic.class);
		this.child.add(SaturnStartIterationNode.class);
		this.child.add(SaturnEndIterationNode.class);
		this.child.add(SaturnTransactionBeginNode.class);
		this.child.add(SaturnTransactionCommitNode.class);
		this.child.add(SaturnTransactionRollBackNode.class);
		this.child.add(SaturnCreatComponentNode.class);
		this.child.add(SaturnPropertyNode.class);
		this.child.add(SaturnStartNodeInAction.class);
		this.child.add(SaturnInformationNodeInAction.class);
		this.child.add(SaturnLogicInAction.class);
		this.child.add(WorkflowInLogicNodeLoader.class);
		this.child.add(SaturnDecisionNodeInAction.class);
	}

	public void doSave(IProgressMonitor monitor) {
		ModelXmlUtils.refreshModelXml(logicEditor.getDiagram());
		this.logicEditor.doSave(monitor);
		textEditor.doSave(monitor);
	}

	public Document getDocument() {
		return document;
	}

	public void doSaveAs() {

	}

	public boolean isSaveAsAllowed() {
		return false;
	}

	public void resourceChanged(IResourceChangeEvent event) {

	}

	@Override
	protected void pageChange(int newPageIndex) {
		if (newPageIndex == this.textEditorIndex) {
			ModelXmlUtils.refreshModelXml(logicEditor.getDiagram());
		}
		super.pageChange(newPageIndex);
	}

	public String getContributorId() {
		return getSite().getId();
	}

	@SuppressWarnings("unchecked")
	public Object getAdapter(Class adapter) {
		if (adapter == IPropertySheetPage.class) {
			return new TabbedPropertySheetPage(this);
		}
		return super.getAdapter(adapter);
	}

	public ShapesDiagram getDiagram() {
		return this.logicEditor.getDiagram();
	}

	public boolean hasChild(Class<?> shape) {
		for (Class<?> c : this.child) {
			if (c == shape) {
				return true;
			}
		}
		return false;
	}

	public Point getMousePoint() {
		return this.logicEditor.getMousePoint();
	}

	public void fakesaveimpl() {
		this.getDiagram().getEditPart().getViewer().getEditDomain()
				.getCommandStack().execute(new FakeCommand());
	}
}
